#ifndef __LIOTOOL_H_
#define __LIOTOOL_H_

#pragma comment(compiler)  
#pragma warning(disable:4996) // No Security Warnings
//#pragma warning(disable:4018) // No Signed/Unsigned Warnings
//#pragma warning(disable:C4089) // Param cast
#pragma warning(disable:4345) // No default constructor warnings
#pragma warning(disable:4297) // No exception throw warnings
#pragma warning(disable:4390) // empty controlled statement found
#pragma warning(disable:4312) // conversion from A to B of greater size
#pragma warning(disable:4512) // assignment operator could not be generated
#pragma warning(disable:4706) // assignment within conditional expression
#pragma warning(disable:4127) // conditional expression is constant

//#define WINVER 0x0501
//#define _WIN32_WINNT WINVER

#include <math.h>				// Math Library Header File
#include <stdarg.h>				// Variable Argument Routines
#include <string.h>				// String Management
#include <direct.h>				// Directory management
#include <memory.h>				// Memory Management
#include <time.h>				// Time Routines
#include <limits.h>				// Number Format Constants
#include <float.h>				// Floating Point Routines
#include <windows.h>			// Windows API Definitions
#include <assert.h>				// Assertions
#include <stdlib.h>				// Standart C Library
#include <stdio.h>				// Standard Input/Output
#include <tchar.h>				// Unicode support
#include <new.h>
#include <string>
#include <omp.h>				// parallel processing

#ifdef  __cplusplus
	extern "C" {
#endif
#include "../extern/mercenne/mercenne.h"
#include "../extern/zlib/zlib.h"
#ifdef  __cplusplus
	}
#endif

#include "../extern/hash/sha1.h"
#include "../extern/hash/lookup3.h"

#define DLLEXPORT extern "C" __declspec(dllexport)
#define DLLIMPORT extern "C" __declspec(dllimport)

#define DIR_NONE 0
#define DIR_RIGHT 1
#define DIR_UP 2
#define DIR_LEFT 4
#define DIR_DOWN 8

#define PLUS 1
#define MINUS (-1)

#ifndef FALSE
#	define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

#define NEW_LINE 13
#define RET_LINE 10

#ifndef NO_ERROR
#	define NO_ERROR 0
#endif

#define TRY_CATCH(exp) try{exp;}catch(...){return FALSE;}return TRUE;

#ifndef NULL
#	ifdef __cplusplus
#		define NULL 0
#	else
#		define NULL ((void *)0)
#	endif
#endif

// RANDOM:
#define USE_MERSENNE_TWISTER

#ifdef USE_MERSENNE_TWISTER
#	define SRAND(seed) init_genrand(seed)
#	define RAND_TO_UNIT (1.0/0xffffffffU) // 2.3283064370807973754314699618685e-10
#	define RAND() genrand_int32()
#else
#	define SRAND(seed) srand(seed)
#	define RAND_TO_UNIT (1.0/RAND_MAX)
#	define RAND() rand()
#endif

#define INITRAND SRAND((UINT)time(NULL)),RAND()

namespace Lio {

enum memTypes {
	MEM_TYPE_EXTERN,
	MEM_TYPE_NEW,
	MEM_TYPE_ALLOC,
	MEM_TYPE_COUNT
};

enum memOperations {
	MEM_OP_NONE,
	MEM_OP_CLEAR,
	MEM_OP_KEEP,
	MEM_OP_COUNT
};

typedef int BOOL;
typedef _TCHAR* STR;
typedef const _TCHAR* CSTR;

enum Errors {
	OUT_OF_BOUNDS_ERROR = -1,
	PARAM_ERROR  = -2,
	IO_ERROR  = -3,
	DATA_ERROR  = -4,
	MEM_ERROR  = -5,
	MATH_ERROR  = -6,
	DIM_ERROR  = -7,
	NULL_POINTER_ERROR  = -8,
};

// Random Number Generators
inline double random()
{// Generates a Random Number [0,1]
	return RAND_TO_UNIT*RAND();
}
inline double random(double max)
{// Generates a Random Number [0,max]
	return max*random();
}
inline double random(double min, double max)
{ // Generates a Random Number [min, max]
	return min+(max-min)*random();
}

// POWER OPERATIONS:
// return x^2
template <typename T>
inline T pow2(T x)
{
	return x*x;
}
// return x^3
template <typename T>
inline T pow3(T x)
{
	return x*x*x;
}
// return x*x*x*...*x
template <typename T>
inline T pown(T x, int n)
{
	double result=1;
	if(n>0)
		for(int i=0;i<n;i++)
			result*=x;
	else if(n<0)
		for(int i=0;i>n;i--)
			result/=x;
	return (T)result;
}
// TRUNC OPERATIONS:
inline int __int(float x)
{
	int retval;
	_asm cvttss2si eax, x
	_asm mov retval, eax
	return retval;
}
inline int __int(double x)
{
	int retval;
	_asm cvttsd2si eax, x
	_asm mov retval, eax
	return retval;
}
// ROUND OPERATIONS:
inline int round(double n)
{
	return __int(n<0.0 ? (n-0.5) : (n+0.5));
}
inline int round(float n)
{
	return __int(n<0.0f ? (n-0.5f) : (n+0.5f));
}
inline double round(double n, int d)
{/* round number n to d decimal points */
	ULONG l=1;
	for(int i=0;i<d;i++)
		l*=10;
	return (n<0)?(floor(n*l-0.5)/l):(floor(n*l+0.5)/l);
}
// COMPARE OPERATIONS:
#define REPLACE(a,b) (a)^=(b)^=(a)^=(b)
template <typename T, typename F>
inline const T& minval(const T& val1, const F& val2)
{
	return T((val1<val2)?val1:val2);
}
template <typename T, typename F>
inline const T& maxval(const T& val1, const F& val2)
{
	return T((val1>val2)?val1:val2);
}
template <typename T>
inline T absval(const T& val)
{
	return (val<0)?(-val):val;
}
template <typename T, typename F>
inline const T& maxabsval(const T& val1, const F& val2)
{
	return (((val1<0)?(-val1):val1)>((val2<0)?(-val2):val2))?val1:val2;
}
template <typename T>
inline T clamp(const T& val, const T& min, const T& max)
{
	return (val<min)?min:(val>max?max:val);
}
#define ABS(val)((val)<0 ? -(val) : (val))
#define SIGN(val)((val)<0 ? -1 : 1)
#define INV(val) (1.0/(val))
#define INVF(val) (1.0f/(val))
// REMAP OPERATIONS:
template <typename G, typename T, typename F>
inline F remap(	const G& value,
				const T& oldMin, const T& oldMax,
				const F& newMin, const F& newMax)
{
	return F(newMin+(T(value)-oldMin)*(newMax-newMin)/(oldMax-oldMin));
}
template <typename G, typename T, typename F>
inline F remap(	const G& value,
				const T& oldMin, const T& oldMid, const T& oldMax,
				const F& newMin, const F& newMid, const F& newMax)
{
	return F((value<oldMid)?
			(newMin+(T(value)-oldMin)*(newMid-newMin)/(oldMid-oldMin)):
			(newMid+(T(value)-oldMid)*(newMax-newMid)/(oldMax-oldMid)));
}

template <typename G, typename T, typename F>
inline F logremap(	const G& value,
					const T& oldMin, const T& oldMax,
					const F& newMin, const F& newMax)
{
	return F(newMin+(newMax-newMin)*log10(value-oldMin+1)/log10(oldMax-oldMin+1));
}
template <typename G, typename T, typename F>
inline F logdemap(	const G& value,
					const T& oldMin, const T& oldMax,
					const F& newMin, const F& newMax)
{
	return F(newMin-1+pow(10,log10(newMax-newMin+1)*(value-oldMin)/(oldMax-oldMin)));
}

template <typename A, typename B, typename C>
inline A bilinearmap(const A& v00, const A& v01, const A& v10, const A& v11, const B& dx, const C& dy)
{
	return A(v00+dx*(v10-v00)+dy*(v01-v00)+dx*dy*(v11-v10-v01+v00));
}

// STR OPERATIONS:
inline int charToNum(_TCHAR c)
{
	if(c>=48&&c<58)
		return c-48;
	if(c>=65&&c<91)
		return c-55;
	if(c>=97&&c<123)
		return c-87;
	return -1;
}
inline _TCHAR numToChar(int n, BOOL upper = FALSE)
{
	if(n>=0&&n<10)// 1 : 9
		return _TCHAR(n+48);
	if(n>=10&&n<36)// A : Z
		return _TCHAR(upper?n+55:n+87);
	return 63;// ?
}
int numToStr(int n, STR s, int length = -1, int system = 10, BOOL upper = FALSE);
int strToNum(STR s, int length = -1, int system = 10);

inline int strLen(CSTR s){return s?(int)_tcsclen(s):0;}
inline BOOL strCmp(CSTR s1, CSTR s2){return (s1==s2)?TRUE:(s1&&s2)?_tcscmp(s1,s2)==0:FALSE;}
inline BOOL strCpy(STR s1, CSTR s2)
{
	if(!s1||!s2)
		return FALSE;
	_tcscpy(s1,s2);
	return TRUE;
}
inline int strIndexOf(CSTR s, _TCHAR c)
{
	if(s)
	{
		CSTR result=_tcschr(s,c);
		if(result)
			return int(result-s);
	}
	return -1;
}
inline int strLastIndexOf(CSTR s, _TCHAR c)
{
	if(s)
	{
		CSTR result=_tcsrchr(s,c);
		if(result)
			return int(result-s);
	}
	return -1;
	
}
inline int strReplace(STR s, _TCHAR oldChar, _TCHAR newChar)
{
	register int i;
	int replaces=0,length=strLen(s);
	if(length)
	{
		for(i=0;i<length;i++)
		{
			if(s[i]==oldChar)
			{
				s[i]=newChar;
				replaces++;
			}
		}
	}
	return replaces;
}

// BIT OPERATIONS:
#define PROPSET(prop,mask,value) ((value)?(prop|=mask):(prop&=~mask))
#define MASK(start,end)((~((~0L)<<((end)-(start)+1)))<<(start))
#define GET_BIT(number,index)((((number)>>(index))&1)==1)
#define SET_BIT(number,index,value)((value)?(number)|(1<<(index)):(number)&(~(1<<(index))))
#define SET_BITS(number,start,end,bits)(((number)&~MASK((start),(end)))|((bits)<<(start)))
#define GET_BITS(number,start,end)(((number)&MASK((start),(end)))>>(start))

#define Clear(ptr) memset((void*)(ptr),0,sizeof(ptr))
#define ClearMemory(ptr, size) memset((void*)(ptr),0,(size_t)(size))
#define ClearArray(table, count) memset((void*)(table),0,sizeof(*(table))*(size_t)(count))
#define ClearStruct(strct) memset((void*)(&strct),0,sizeof(strct))

inline int readIntL(BYTE *b, int count = 4, int index = 0)
{
	int n=0;
	for(int i=0;i<count;i++)
		n|=b[index+i]<<(i*8);
    return n;
}
inline int readIntB(BYTE *b, int count = 4, int index = 0)
{
    int n=0;
	for(int i=0;i<count;i++)
		n|=b[index+count-i-1]<<(i*8);
    return n;
}
inline void writeIntL(int n, BYTE *b, int count = 4, int index = 0)
{
	for(int i=0;i<count;i++)
		b[index+i]=(n>>(i*8))&0xff;
}
inline void writeIntB(int n, BYTE *b, int count = 4, int index = 0)
{
    for(int i=0;i<count;i++)
		b[index+count-i-1]=(n>>(i*8))&0xff;
}

void SetThreadName(LPCSTR name, DWORD threadID = ~0U);

class PrecisionTimer
{
protected:
	__int64 counts_per_second, start_counter;
	float seconds_per_count;
public:
	float last_time;
	PrecisionTimer():counts_per_second(0),start_counter(0),last_time(0),seconds_per_count(0)
	{
		LARGE_INTEGER tmp;
		if(!QueryPerformanceFrequency(&tmp))
			return;
		if(counts_per_second=(__int64)tmp.QuadPart)
			seconds_per_count=(float)INV(counts_per_second);
		restart();
	}
	float time(BOOL reset = FALSE)
	{
		LARGE_INTEGER tmp;
		if(!QueryPerformanceCounter(&tmp))
			return 0;
		__int64 counter = (__int64)tmp.QuadPart;
		last_time=((UINT64)(counter-start_counter))*seconds_per_count;
		if(reset)
			start_counter=counter;
		return last_time;
	}
	float restart(){return time(TRUE);}
};

class Mutex // Process synchronization class
{
public:
	HANDLE hMutex;
	LPCTSTR name;
	DWORD error;
	Mutex(LPCTSTR name0 = NULL, BOOL aquired = FALSE);
	~Mutex();
	BOOL start(DWORD waitTime = INFINITE);
	BOOL stop();
	
	BOOL wait(DWORD waitTime = INFINITE){return start(waitTime)?stop():FALSE;}
};

class CriticalSection // Thread synchronization class
{
protected:
	CRITICAL_SECTION critical_section;
public:
	CriticalSection()
	{
		InitializeCriticalSection(&critical_section);
	}
	~CriticalSection()
	{
		DeleteCriticalSection(&critical_section);
	}
	void Enter()
	{
		EnterCriticalSection(&critical_section);
	}
	void Leave()
	{
		LeaveCriticalSection(&critical_section);
	}
	void Wait()
	{
		EnterCriticalSection(&critical_section);
		LeaveCriticalSection(&critical_section);
	}
};

class Lock
{
private:
	CriticalSection *__cs;
public:
	Lock(CriticalSection *cs):__cs(NULL)
	{
		if(!cs)
			return;
		cs->Enter();
		__cs=cs;
	}
	~Lock()
	{
		if(!__cs)
			return;
		__cs->Leave();
	}
};

class File
{
protected:
	FILE *file;
	int id;
public:
	File():file(NULL),id(-1)
	{}
	~File()
	{
		close();
	}
	BOOL open(CSTR fileName, CSTR mode = _T("rb"))
	{
		close();
		if(fileName&&mode)
		{
			file=_tfopen(fileName,mode);
			if(file)
			{
				id=_fileno(file);
				return TRUE;
			}
		}
		return FALSE;
	}
	void close()
	{
		if(file)
		{
			fclose(file);
			file=NULL;
			id=-1;
		}
	}
	long length();
	template <typename T>
	BOOL read(T *values, int count = 1)
	{
		return (!file||!values||count<1)?FALSE:fread(values,sizeof(T),count,file)==(UINT)count;
	}
	template <typename T>
	BOOL write(const T *values, int count = 1)
	{
		return (!file||!values||count<1)?FALSE:fwrite(values,sizeof(T),count,file)==(UINT)count;
	}
	BOOL seek(long offset, int origin = SEEK_SET)
	{
		return (file)?fseek(file,offset,origin)==0:FALSE;
	}
	long tell()
	{
		return (file)?ftell(file):-1L;
	}
	BOOL eof()
	{
		return (file)?(feof(file)!=0):TRUE;
	}
	BOOL error()
	{
		return (file)?(ferror(file)!=0):FALSE;
	}
	int descript() const
	{
		return id;
	}
	long indexOf(BYTE c, long start = 0);
	long indexOf(const BYTE* block, size_t size, long start = 0);
	operator FILE*(){return file;}
	operator int(){return id;}
};
template <typename T> class Point2d
{
public:
	T x,y;
	Point2d():x(0),y(0){}
	Point2d(const T& x0, const T& y0):x(x0),y(y0){}
	void copy(const Point2d &point)
	{
		x=point.x;
		y=point.y;
	}
	double dist(const Point2d<T> &point) const
	{
		return getLength(x-point.x,y-point.y);
	}
	double dist(const T& cx, const T& cy) const
	{
		return getLength(x-cx,y-cy);
	}
	double dist() const
	{
		return getLength(x,y);
	}
	double square(const Point2d<T> &point) const
	{
		return (x-point.x)*(x-point.x)+(y-point.y)*(y-point.y);
	}
	double square(const T& cx, const T& cy) const
	{
		return (x-cx)*(x-cx)+(y-cy)*(y-cy);
	}
	double square() const
	{
		return x*x+y*y;
	}
	void set(const T& x, const T& y)
	{
		this->x=x;
		this->y=y;
	}
	Point2d<T>& operator =(const Point2d<T> &point)
	{
		copy(point);
		return *this;
	}
	BOOL operator ==(const Point2d<T> &point)
	{
		return equals(point);
	}
	BOOL operator !=(const Point2d<T> &point)
	{
		return !equals(point);
	}
	BOOL equals(const Point2d<T> &point)
	{
		return (x==point.x)&&(y==point.y);
	}
	BOOL equals(const T& cx, const T& cy)
	{
		return (x==cx)&&(y==cy);
	}
};

template <typename T> class Point3d
{
public:
	T x,y,z;
	Point3d():x(0),y(0),z(0){}
	Point3d(const T& x0, const T& y0, const T& z0):x(x0),y(y0),z(z0){}
	void copy(const Point3d &point)
	{
		x=point.x;
		y=point.y;
		z=point.z;
	}
	void set(const T& x, const T& y, const T& z)
	{
		this->x=x;
		this->y=y;
		this->z=z;
	}
	double dist(const Point3d<T> &point) const
	{
		return sqrt(pow2(x-point.x)+pow2(y-point.y)+pow2(z-point.z));
	}
	double dist(const T& cx, const T& cy, const T& cz) const
	{
		return sqrt(pow2(x-cx)+pow2(y-cy)+pow2(z-cz));
	}
	double dist() const
	{
		return sqrt(pow2(x)+pow2(y)+pow2(z));
	}
	double square() const
	{
		return x*x+y*y+z*z;
	}
	Point3d<T>& operator =(const Point3d<T> &point)
	{
		copy(point);
		return *this;
	}
};

template <typename T> class Rect
{
public:
	T x,y,width,height;
	Rect():x(0),y(0),width(0),height(0){}
	Rect(const T& x0, const T& y0, const T& w, const T& h):
		x(x0),y(y0),width(w),height(h){}
	void copy(const Rect &rect)
	{
		x=rect.x;
		y=rect.y;
		width=rect.width;
		height=rect.height;
	}
	void set(const T& x0, const T& y0, const T& w, const T& h)
	{
		x=x0;
		y=y0;
		width=w;
		height=h;
	}
	void set(const Point2d<T>& location, const Point2d<T>& size)
	{
		x=location.x;
		y=location.y;
		width=size.x;
		height=size.y;
	}
	void shift(const T& dx, const T& dy)
	{
		x+=dx;
		y+=dy;
	}
	void zoom(const T& kx, const T& ky)
	{
		width*=kx;
		height*=ky;
	}
	T area() const
	{
		return width*height;
	}
	BOOL contain(const T& x0, const T& y0) const
	{
		return x0>=x&&x0<=(x+width)&&y0>=y&&y0<=(y+height);
	}
	BOOL contain(const Rect<T>& rect) const
	{
		return contain(rect.x,rect.y)&&contain(rect.x+rect.width,rect.y+rect.height);
	}
	double ratiox(const T& x0) const
	{
		if(width)
			return (double(x0-x))/width;
		return 0;
	}
	double ratioy(const T& y0) const
	{
		if(height)
			return (double(y0-y))/height;
		return 0;
	}
	T centerx() const
	{
		return x+0.5*width;
	}
	T centery() const
	{
		return y+0.5*height;
	}
	T left() const
	{
		return x;
	}
	T right() const
	{
		return x+width;
	}
	T top() const
	{
		return y;
	}
	T bottom() const
	{
		return y+height;
	}
	Rect<T>& operator =(const Rect<T> &rect)
	{
		copy(rect);
		return *this;
	}
};

class NumberFormat
{
public:
	_TCHAR 
		format[13],
		string[MAX_PATH],
		sign;
	char
		minWidth,
		maxWidth,
		precision;
	BOOL 
		exposant,
		zeros,
		uppercase,
		hexa;
	NumberFormat():	minWidth(0),
					maxWidth(-1),
					precision(-1),
					hexa(0),
					exposant(0),
					sign(0),
					zeros(0),
					uppercase(0)
	{}
	NumberFormat(const NumberFormat &model)
	{
		copy(model);
	}
	void set(	_TCHAR precision,
				_TCHAR minWidth = 0,
				BOOL exposant = FALSE,
				_TCHAR sign = 0,
				BOOL zeros = FALSE,
				BOOL uppercase = FALSE,
				_TCHAR maxWidth = -1);
	void copy(const NumberFormat &model);
	NumberFormat& operator =(const NumberFormat &model)
	{
		copy(model);
		return *this;
	}
	CSTR toString(int n, CSTR fmt = NULL);
	CSTR toString(double n, CSTR fmt = NULL);
	int toInt(CSTR s, int defValue = 0, CSTR fmt = NULL);
	double toDouble(CSTR s, double defValue = 0.0, CSTR fmt = NULL);
};

inline DWORD toHash(const void *src, unsigned int size)
{
	return lookup3::hashlittle(src, size, 0);
}
inline DWORD toHash(CSTR str)
{
	return toHash(str, strLen(str)*sizeof(_TCHAR));
}

class Sha1
{
	unsigned char hash[20];
public:
	Sha1()
	{
		Clear(hash);
	}
	Sha1(CSTR str)
	{
		set(str);
	}
	Sha1(const Sha1& hash)
	{
		set(hash);
	}
	void set(const void *data, int len)
	{
		if(!data||len<=0)
		{
			Clear(hash);
			return;
		}
		sha1::calc(data, len, hash);
	}
	void set(const Sha1& hash)
	{
		memcpy(this->hash, hash.hash, 20);
	}
	void set(CSTR str)
	{
		set((const void *)str, strLen(str)*sizeof(_TCHAR));
	}
	BOOL equals(const unsigned char *hash)
	{
		return memcmp(this->hash, hash, 20) == 0;
	}
	BOOL equals(const Sha1 &hash)
	{
		return equals(hash.hash);
	}
	Sha1& operator =(const Sha1& hash){set(hash);return *this;}
	Sha1& operator =(CSTR str){set(str);return *this;}
	BOOL operator ==(const Sha1& hash){return equals(hash);}
	BOOL operator !=(const Sha1& hash){return !equals(hash);}
#ifndef DEBUG
	void print(FILE *file = stdout)
	{
		char hex[41];
		sha1::toHexString(hash, hex);
		fprintf(file, hex);
	}
#else
	void print(FILE *){}
#endif
};

class Event
{
protected:
	HANDLE m_handle;

public:
	Event(bool bManualReset = false, char *pEventName = 0);
	~Event();
	bool IsSignaled() const;
	bool Wait(int timeout = -1) const;
	void Signal() const;
	void Reset() const;
};

}; //namespace Lio

#endif